const fs       = require('fs'),
	http       = require('http'),
	gulp       = require('gulp'),
	del        = require('del'),                              // 删除
	toIco      = require('to-ico'),                           // 转换 ico
	replace    = require('gulp-replace'),                     // 替换
	uglify     = require('gulp-uglify'),                      // 压缩JS
	rename     = require('gulp-rename'),                      // 重命名
	argv       = require('minimist')(process.argv.slice(2)),  // 命令行传参
	sass       = require("gulp-sass"),                        // 编译 Sass
	cleanCss   = require('gulp-clean-css'),                   // 压缩 CSS
	zip        = require('gulp-zip'),                         // 创建压缩包
	autoprefix = require("gulp-autoprefixer");                // 处理 CSS 浏览器前缀

const devPath = 'source/',
	pagePath  = 'pages/',
	jsPath    = {source: devPath + 'js/',   dest: 'include/js/'},
	cssPath   = {source: devPath + 'scss/', dest: 'include/css/'},
	fontPath  = {dest: 'include/fonts/'};

//\\----------------------------------------------------------------------------//\\

/**
 * JS 任务
 * @desc 复制并压缩 js
 * @param {string} fileName - 用以动态匹配文件名，如果是 * 则代表全部
 */
function runJSTask(fileName) {
	gulp.src(jsPath.source + fileName)    // 1. 找到文件
		.pipe(uglify({ mangle: false }))  // 2. 压缩文件
		.pipe(rename({suffix: '.min'}))   // 3. 重命名
		.pipe(gulp.dest(jsPath.dest))     // 4. 另存文件
		.on('end', function() {
			console.log('[Done] JS 任务处理完毕');
		});
}

//\\----------------------------------------------------------------------------//\\

/**
 * CSS 任务
 * @desc 编译并压缩 css
 * @param {string} fileName - 参考 JS 任务
 */
function runCSSTask(fileName) {
	gulp.src(cssPath.source + fileName)  // 1. 找到文件
		.pipe(sass())                    // 2. 编译 Sass
		.pipe(autoprefix({               // 3. 处理浏览器前缀
			browsers: ['last 10 versions', '> 5%', 'ie 9']
		}))
		.pipe(cleanCss())                // 4. 压缩 CSS
		.pipe(rename({suffix: '.min'}))  // 5. 重命名
		.pipe(gulp.dest(cssPath.dest))   // 6. 另存文件
		.on('end', function() {
			console.log('[Done] CSS 任务处理完毕');
		});
}

/*
function concatCSS(fontCSSPath) {
	var publicCSSName = 'public.min.css',
		publicCSSPath = cssPath.dest + publicCSSName;

	gulp.src([publicCSSPath, fontCSSPath])
		.pipe(concatCss(publicCSSName.split('.')[0] + '.pack.css'))
		.pipe(cleanCss())
		.pipe(gulp.dest(cssPath.dest))
		.on('end', function() {  // 任务流结束后执行
			// 清理合并后的原文件
			del([publicCSSPath, fontCSSPath]);
		});

	console.log('[Done] 已合并 CSS：' + publicCSSPath + ', ' + fontCSSPath);
}
*/

//\\----------------------------------------------------------------------------//\\

/**
 * 拉取第三方网站上生成的 iconfont 资源
 * @desc 资源拉取自：阿里巴巴矢量图标库 (iconfont.cn)
 */
function runIconFontTask() {
	loadConfigFile(function(data) {
		var iconfontURL = data.iconfont.url,
			fontType = data.iconfont.type;

		http.get('http:' + iconfontURL, function(res) {
			res.setEncoding('utf8');

			var cssContent = '';  // 内容字符串

			// 下载数据
			res.on('data', function(chunk) {
				cssContent += chunk;
			});

			// 下载完成
			res.on('end', function() {
				var regRule = new RegExp(/(?=url\(\W)\S+(?=\W\))/, 'g');  // output: url('//xxx//xx.xx?t=xxxxx
				var fontURLs = getFontURLs(cssContent, fontType, regRule);

				modifyFontCSS(fontURLs, cssContent, regRule);
				downloadFonts(fontURLs);
			});
		});
	});
}

/**
 * 从 CSS 文本中解析出字体的地址
 * @param {string} content - 下载的 iconfont CSS 文件文本内容
 * @param {object} regEx - 正则表达式
 */
function getFontURLs(content, fontType, regEx) {
    var fontURLs = [];  // output: url('//xxx//xx.xx?t=xxxxx

    content.replace(regEx, function(match) {
        fontURLs.push(match);  // 保存从 CSS 文件中解析出的字体地址
    });

    // 处理 fontURLs 使其格式合法化
    fontURLs = fontURLs.map(function(item) {
        if (item.indexOf('data:application') === -1) {  // base64 形式的字体
            item = item.replace(/url\(\W/, '').split('?t=')[0];  // output: //xxx//xx.xx

            // 筛选 fontType 中设置的字体类型
            for (var i = 0; i < fontType.length; i++) {
                if (item.lastIndexOf('.' + fontType[i]) > 0) {
                    return item;
                }
            }
        }
    });

    return removeRepeat(fontURLs);  // 移除空值，合并重复 url
}

/**
 * 修改 CSS 中字体远程路径为本地路径
 * @param {array} fonts - 字体路径数组
 * @param {string} data - CSS 文本内容
 * @param {regExp} regEx - 正则
 */
function modifyFontCSS(fonts, data, regEx) {
    fonts.forEach(item => {
        var fontName = returnFontName(item),
            fontHost = item.replace(fontName, ''),
            regEx = new RegExp(fontHost + fontName, 'g');

        data = data.replace(regEx, function(match) {
            return '../fonts/' + fontName;
        });
    });

	// 将调整完字体路径的 CSS 写入本地
	var cssName = 'iconfont.css',
    	localCSSFile = cssPath.source + cssName;

    fs.writeFile(localCSSFile, data, function (err) {
        if (err) {
            throw err;
		}

		runCSSTask(cssName);
    });
}

/**
 * 从远程地址下载字体到本地
 * @param {array} urlArr - 字体远程地址
 */
function downloadFonts(urlArr) {
    urlArr.forEach(url => {
        var fileName = returnFontName(url),
            fileStream = fs.createWriteStream(
                fontPath.dest + fileName
            );

        http.get('http:' + url, function(res) {
            res.pipe(fileStream);  // 文件流写入

            // 下载完成
            res.on('end', function() {
                console.log('[Done] 下载成功：' + fileName);
            });
        });
    });
}

/**
 * 返回 url 地址中的字体名称
 * @param {string} url - 字体 url 地址
 * @returns {string} 字体名称
 */
function returnFontName(url) {
    return url.substr(url.lastIndexOf('/') + 1);
}

//\\----------------------------------------------------------------------------//\\

// 生成 favicon.ico
function runFaviconTask(logoPath) {
	var files = [fs.readFileSync(logoPath)];

	toIco(files, {
		resize: true,
		sizes: [32]  // 默认尺寸为 32*32px
	}).then(buf => {
		fs.writeFile('favicon.ico', buf, function(err) {
			if (err) {
				throw err;
			}

			console.log('[Done] 生成文件：favicon.ico');
		});
	});
}

//\\----------------------------------------------------------------------------//\\

function runBuildTask(isForce) {
	loadConfigFile(function(data) {
		buildEntryFile(data.project);
		buildNavJson(data.nav);
		buildInnerPage(data.nav, isForce);
	});
}

// 构建入口文件 index.html
function buildEntryFile(data) {
	gulp.src(devPath + 'models/index.html')
		.pipe(replace('{{ title }}', function() {
			return data.title;
		}))
		.pipe(replace('{{ name }}', function() {
			return data.name;
		}))
		.pipe(replace('{{ logoPath }}', function() {
			return data.logo;
		}))
		.pipe(rename(data.entry))
		.pipe(gulp.dest('./'))
		.on('end', function() {
			console.log('[Done] 生成文件：' + data.entry);
		});
}

// 构建导航文件 - nav.json
function buildNavJson(data) {
	fs.writeFile('include/js/nav.json', JSON.stringify(data, null, 2), function(err) {
		if (err) {
			throw err;
		}

		console.log('[Done] 已生成 nav.json 文件');
	});
}

// 根据导航构建内页
function buildInnerPage(data, isForce) {
	var _getFileName = function(url) {
		if (url.indexOf('/') > -1) {  // 多级目录
			return url.substr(url.lastIndexOf('/'));
		}
		return url
	};

	data.forEach(nav => {
		if (nav['subNav'] && nav['subNav'].length) {  // 有二级导航
			var base = nav['base'] || '';

			nav['subNav'].forEach(subNav => {
				var filePath = base + subNav['url'],
					fileName = _getFileName(subNav['url']);

				buildFrameFile(subNav, filePath, fileName, isForce);
			});
		} else {
			var filePath = nav['url'],
				fileName = _getFileName(nav['url']);

			buildFrameFile(nav, filePath, fileName, isForce);
		}
	});
}

// 构建内页栏目页面
function buildFrameFile(data, filePath, fileName, isForce) {
	fs.exists(filePath, function(isExists) {
		if (isExists && !isForce) {
			console.log('[warning] ' + filePath + ' 已存在，跳过该文件');
		} else {
			gulp.src(devPath + 'models/frame.html')
				.pipe(replace(/\{\{\stitle\s\}\}/g, function() {
					return data['name'];
				}))
				.pipe(replace(/\{\{\spath\s\}\}/g, function() {
					var pathStr = '';

					for (var i = 0; i < filePath.split('/').length - 1; i++) {
						pathStr += '../';  // 基于 include 的相对位置
					}
					return pathStr;
				}))
				.pipe(rename(fileName))
				.pipe(gulp.dest(filePath.replace(fileName, '')))
				.on('end', function() {
					console.log('[Done] 生成文件：' + filePath);
				});
		}
	});
}

//\\----------------------------------------------------------------------------//\\

// 启动 HTTP 服务
function startHTTPServe() {
	let url = require('url'),
	path = require('path'),
	mine = {
		'css' : 'text/css',
		'gif' : 'image/gif',
		'html': 'text/html',
		'ico' : 'image/x-icon',
		'jpeg': 'image/jpeg',
		'jpg' : 'image/jpeg',
		'js'  : 'text/javascript',
		'json': 'application/json',
		'pdf' : 'application/pdf',
		'png' : 'image/png',
		'svg' : 'image/svg+xml',
		'tiff': 'image/tiff',
		'txt' : 'text/plain'
	},
	port = 8888;

	// 写入页面并启动服务
	http.createServer(function(req, res) {
		var pathname = url.parse(req.url).pathname,
			realPath = path.join('./', pathname),
			ext = path.extname(pathname);

		ext = ext ? ext.slice(1) : 'unknown';

		fs.exists(realPath, function(exists) {
			if (!exists) {
				res.writeHead(404, {
					'Content-Type': 'text/plain'
				});

				res.write('This request URL ' + realPath + ' was not found on this server.');
				res.end();
			} else {
				fs.readFile(realPath, 'binary', function(err, file) {
					if (err) {
						res.writeHead(500, {
							'Content-Type': 'text/plain'
						});
						res.end(err);
					} else {
						var contentType = mine[ext] || 'text/plain';

						res.writeHead(200, {
							'Content-Type': contentType
						});
						res.write(file, 'binary');
						res.end();
					}
				});
			}
		});
	}).listen(port);

	console.log('HTTP 服务已启动');

	// 开启网页
	var cmd = require('child_process');
	cmd.exec('start http://127.0.0.1:' + port + '/index.html');
}

//\\----------------------------------------------------------------------------//\\

/**
 * 获取文件名
 */
function getFileName(param, type) {
	var fileName = '*.' + type;

	if (param && typeof param === 'string') {
		var flag = param.lastIndexOf('.' + type);

		if (flag > 0) {
			fileName = param;
		} else {
			fileName = param + '.' + type;
		}
	}

	return fileName;
}

/**
 * 数组去重、去空值
 * @param {array} arr - 待处理数组
 * @returns {array} 合并重复项的数组
 */
function removeRepeat(arr) {
    var result = [],
        hash = {};

    for (var i = 0, elm; i < arr.length; i++) {
        if (arr[i]) {
            (elm = arr[i]) != null;
            if (!hash[elm]) {
                result.push(arr[i]);
                hash[elm] = true;
            }
        }
    }

    return result;
}

/**
 * 读取配置文件
 * @param {function} callback - 回调函数
 */
function loadConfigFile(callback) {
	fs.readFile(devPath + 'project.json', {
		encoding: 'utf-8'
	}, function(err, data) {
		var data = JSON.parse(data);
		callback(data);
	});
}

//\\----------------------------------------------------------------------------//\\

gulp.task('default', function() {
	var graphic =
		'+--------------------------------------------------------+\n' +
		'|          //          　/////////         //     //     |\n' +
		'|        // //        　//       //      // //  // //    |\n' +
		'|      //    //       　//////////      //  ////   //    |\n' +
		'|    //////////     　//   //         //    //     //    |\n' +
		'|  //         //    //     //////    //            //    |\n' +
		'+--------------------------------------------------------+\n';

	console.log(graphic);
});

/**
 * @example
 *  1. gulp js - 处理所有 js 文件
 *  2. gulp js --name index.js - 只处理 index.js
 */
gulp.task('js', function() {
	// 编译指定文件：gulp js --name public.js
	var param = getFileName(argv.name, 'js');
	runJSTask(param);
});

gulp.task('css', function() {
	var param = getFileName(argv.name, 'scss');
	runCSSTask(param);
});

gulp.task('font', function() {
	del([fontPath.dest + '*.*']).then(function(paths) {
		console.log('[Done] 已清理旧字体文件：\n', paths.join('\n'));
		runIconFontTask();
	});
});

gulp.task('favicon', function() {
	var param = argv.name,
		path = 'include/images/' + param;

	if (param && typeof param === 'string') {
		runFaviconTask(path);
	} else {
		loadConfigFile(function(data) {
			runFaviconTask(data.project.logo);
		});
	}
});

gulp.task('build', function() {
	var isForce = argv.force;  // 是否强制模式

	runBuildTask(isForce);
});

gulp.task('serve', function() {
	startHTTPServe();
});

gulp.task('zip', function() {
	const output = 'export',
		zipFile = 'armui_dist.zip';

	console.log('[Running] 打包中...');

	// 生产包
	gulp.src(['include*/**', '*.html', 'favicon.ico'])
		.pipe(zip(zipFile))
		.pipe(gulp.dest(output))
		.on('end', function() {
			fs.exists(output + '/' + zipFile, function(isExists) {
				if (isExists) {
					console.log('[Done] 打包完成：' + zipFile);
				} else {
					console.log('[Error] 打包失败，请重试！');
				}
			});
		});
});
